export {}

class Person {
  name: string // 必须在这里声明一下，否则在构造函数中直接赋值会报错提示name不存在
  age: number = 18 // 类的属性必须有一个初始值，可使用等号赋值，或构造函数中初始化，二者必有其一

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  
  // 可定义参数类型 & 返回值类型
  sayHi (msg: number): void {
    // 在函数内部也可以是用 this 获取变量
    console.log(`hi, I'm ${this.name}, ${msg}`)
  }
}

/**
 * 访问修饰符
 */
class Person1 {
  public name: string // 公有成员（默认是public，因此可写可不写）
  private age: number = 18 // 私有属性只能在类的内部使用
  protected gender: boolean // 受保护的成员

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
    this.gender = true
  }
  
  sayHi (msg: string): void {
    console.log(`hi, I'm ${this.name}, ${msg}`)
    console.log(this.gender)
  }
}
const tom = new Person1('tom', 20)
console.log(tom.name)
tom.sayHi('这是一句话')
// console.log(tom.age) // Property 'age' is private and only accessible within class 'Person1'
// console.log(tom.gender) // Property 'gender' is protected and only accessible within class 'Person1' and its subclasses

class Student1 extends Person1{
  private constructor(name: string, age: number) {
    super(name, age) // 调用父类构造函数
    console.log(this.gender)
  }

  // 定义静态方法，使用 new 的方式创建类的实例，因为 new 的方式就是调用了此类型的构造函数
  static create(name: string, age: number) {
    return new Student1(name, age)
  }
}
// const student = new Student1('jack', 12) // Constructor of class 'Student1' is private and only accessible within the class declaration.
const student = Student1.create('jack', 12)

/**
 * 只读属性
 */
class Person2 {
  name: string
  age: number = 18
  protected readonly gender: boolean

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
    this.gender = true
  }
  
  // 可定义参数类型 & 返回值类型
  sayHi (msg: number): void {
    // 在函数内部也可以是用 this 获取变量
    console.log(`hi, I'm ${this.name}, ${msg}`)
  }
}
const sam = new Person2('sam', 20)
// sam.gender = false // Property 'gender' is protected and only accessible within class 'Person2' and its subclasses.